<?php
/**
 * Soar Framework - Lightweight and simple to use PHP Framework
 *
 * Soar is free software and is distributed WITHOUT ANY WARRANTY
 *
 * @package Soar
 * @version 1.0 $Id: SoarConf.php 2 2012-04-06 21:50:33Z shay@shayanderson.com $
 * @copyright Copyright (c) 2012 ShayAnderson.com
 * @license http://www.gnu.org/licenses/gpl.html GPL License
 * @link http://www.shayanderson.com/projects/soar-php-framework.htm
 */

/**
 * Soar Framework Configuration Class
 *
 * @package Soar
 * @name SoarConf
 * @author Shay Anderson 03.12
 *
 * @example
 * // add config file
 * SoarConf::file('./conf.php');
 * './config.php' contains:
 * <?php return array(
 *		'app' => array(
 *			'ver' => 1.0,
 *			'server' => 'dev'
 *		);
 * ); ?>
 * // get instance
 * $conf = &SoarConf::getInstance();
 * echo $conf->app->ver; // 1.0
 * echo $conf->app->server; // dev
 */
final class SoarConf extends SoarSingleton
{
	/**
	 * All config nodes
	 *
	 * @var stdClass
	 */
	public $conf;

	/**
	 * Init
	 */
	protected function __construct()
	{
		$this->conf = new stdClass;
	}

	/**
	 * Config setting getter
	 *
	 * @param string $key
	 * @return mixed
	 */
	public function __get($key)
	{
		if(!$this->__isset($key))
		{
			trigger_error("Invalid configuration key \"{$key}\", "
				. 'key does not exist', SoarErrorHandler::ERROR);
		}
		return $this->conf->{$key};
	}

	/**
	 * Check if config setting exists
	 *
	 * @param string $key
	 * @return bool
	 */
	public function __isset($key)
	{
		return isset($this->conf->{$key});
	}

	/**
	 * Add config node
	 *
	 * @param string $node_name
	 * @param mixed $value
	 * @param SoarConfNode $last_node
	 */
	private function __node($node_name, $value = NULL, SoarConfNode &$last_node)
	{
		if(!is_array($value))
		{
			if(!isset($last_node->{$node_name}))
			{
				$last_node->{$node_name} = $value;
			}
		}
		else
		{
			if(!isset($last_node->{$node_name}))
			{
				$last_node->{$node_name} = new SoarConfNode($last_node->getPath()
					. '->' . $node_name);
			}
			$last_node = &$last_node->{$node_name};
			foreach($value as $k => $v)
			{
				$this->__node($k, $v, $last_node);
			}
		}
	}

	/**
	 * Config setting setter
	 *
	 * @param string $key
	 * @param mixed $value
	 * @return void
	 */
	public function __set($key, $value)
	{
		$this->conf->{$key} = $value;
	}

	/**
	 * Add config file
	 *
	 * @param string $conf_path
	 * @return void
	 */
	public static function file($conf_path)
	{
		if(empty($conf_path) || !is_readable($conf_path))
		{
			trigger_error("Failed to read configuration file \"{$conf_path}\"",
				SoarErrorHandler::ERROR);
		}
		$tmp_conf = require $conf_path;
		if(!is_array($tmp_conf))
		{
			trigger_error("Failed to load configuration file \"{$conf_path}\","
				. ' invalid configuration type (must be array)', SoarErrorHandler::ERROR);
		}
		foreach($tmp_conf as $k => $v)
		{
			if(is_array($v))
			{
				if(!isset(self::getInstance()->conf->{$k}))
				{
					self::getInstance()->conf->{$k} = new SoarConfNode($k);
				}
				foreach($v as $l => $w)
				{
					self::getInstance()->__node($l, $w, self::getInstance()->conf->{$k});
				}
			}
		}
		unset($tmp_conf);
		Soar::log(__CLASS__ . ': file "' . $conf_path . '" initialized', SoarDebugger::LEVEL_DEBUG);
	}

	/**
	 * Get self instance (singleton)
	 *
	 * @return SoarConf
	 */
	public static function &getInstance()
	{
		parent::$_class_name = __CLASS__;
		return parent::getInstance();
	}
}
?>